package edu.zju.gis.dbfg.fileserver.controller;

import edu.zju.gis.dbfg.common.Result;
import edu.zju.gis.dbfg.common.constant.CodeConstants;
import edu.zju.gis.dbfg.fileserver.config.BackendFileSystemConfiguration;

import edu.zju.gis.dbfg.fileserver.operator.FileOperator;
import edu.zju.gis.dbfg.fileserver.util.LocalFileIOUtil;
import edu.zju.gis.dbfg.fileserver.util.reader.ShpFileReader;
import org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload;
import org.json.simple.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;

import static edu.zju.gis.dbfg.fileserver.common.Seprator.TAB;


@CrossOrigin
@Controller
@RequestMapping("/userSpace")
public class UserSpaceController {
    @Autowired
    private BackendFileSystemConfiguration fileSetting;
    @Autowired
    private FileOperator fileOperator;

    private static final int PREVIEW_SIZE = 20;

    @RequestMapping(value = "/all", method = RequestMethod.GET)
    @ResponseBody
    public Result getSubfiles(@SessionAttribute("userId") String userId, String path) throws IOException {
        String userPath = getUserPath(userId, path);
        if (userPath.equals("ERROR"))
            return Result.error("无用户登陆状态。");
        if (!fileOperator.exist(userPath))
            return Result.error().setMessage("Path is not exist.");
        if (!fileOperator.isDirectory(userPath))
            return Result.error().setMessage("Path is not Directory.");
        List<Map<String, String>> files = new ArrayList<>();
        File[] allFiles = fileOperator.getAllFilePaths(userPath);
        for (int i = 0; i < allFiles.length; i++) {
            Map<String, String> pathInfo = new HashMap<>();
            pathInfo.put("Name", allFiles[i].getName());
            pathInfo.put("Type", allFiles[i].isDirectory() ? "Directory" : "File");
            if (pathInfo.get("Type").equals("Directory")) {
                pathInfo.put("Size", "...");
            } else {
                pathInfo.put("Size", getPrintSize(allFiles[i].length()));
            }
            Date date = new Date(allFiles[i].lastModified());
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String str = sdf.format(date);
            pathInfo.put("Date", str);
            files.add(pathInfo);
        }
        return Result.success().setBody(files);
    }

    @RequestMapping(value = "/new/{fileOrDir}", method = RequestMethod.POST)
    @ResponseBody
    public Result newFileOrDir(@SessionAttribute("userId") String userId, @PathVariable String fileOrDir, String path) throws IOException {
        String userPath = getUserPath(userId, path);
        if (fileOperator.create(userPath, fileOrDir.equals("file")))
            return Result.success().setMessage("创建成功");
        else
            return Result.error().setMessage("创建失败");
    }

    @RequestMapping(value = "/upload", method = RequestMethod.POST)
    @ResponseBody
    public Result upload(@SessionAttribute("userId") String userId, HttpServletRequest request, String path) {
        if (!ServletFileUpload.isMultipartContent(request)) {//判断是否为包含文件的表单数据
            return Result.error().setMessage("请选择上传文件。");
        }
        StringBuilder sb = new StringBuilder();
        List<MultipartFile> files = ((MultipartHttpServletRequest) request).getFiles("file");//获取name为file的文件（表单中name可重复）
        for (int i = 0; i < files.size(); i++) {
            try {
                String filename = files.get(i) != null ? files.get(i).getOriginalFilename() : "Error";
                String savePath = getUserPath(userId, path + "/" + filename);
                InputStream inputStream = files.get(i).getInputStream();
                OutputStream outputStream = new FileOutputStream(savePath);
                if (fileOperator.upload(outputStream, inputStream))
                    sb.append("Success: " + filename + ";");
                else
                    sb.append("Error: " + filename + ";");
            } catch (Exception e) {
                return Result.error().setMessage("文件上传失败:" + sb.toString() + e);
            }
        }
        return Result.success().setMessage(sb.toString());
    }

    @RequestMapping(value = "/download", method = RequestMethod.GET)
    @ResponseBody
    public Result download(@SessionAttribute("userId") String userId, HttpServletResponse response, String path) {
        String userPath = getUserPath(userId, path);
        try {
            if (!fileOperator.exist(userPath))
                return Result.error().setMessage("Path is not exist.");
            if (fileOperator.isDirectory(userPath))
                return Result.error().setMessage("Path is not file.");
            fileOperator.download(userPath, response);
            return Result.success();
        } catch (Exception e) {
            return Result.error();
        }
    }

    @RequestMapping(value = "/delete", method = RequestMethod.GET)
    @ResponseBody
    public Result delete(@SessionAttribute("userId") String userId, String path) {
        String userPath = getUserPath(userId, path);
        try {
            if (fileOperator.isDirectory(userPath))
                fileOperator.deletePath(userPath);
            else
                fileOperator.deleteFile(userPath);
            return Result.success().setMessage("删除成功");
        } catch (IOException e) {
            e.printStackTrace();
            return Result.error().setMessage("删除失败：" + e);
        }
    }

    @RequestMapping(value = "/preview", method = RequestMethod.GET)
    @ResponseBody
    public Result preview(@SessionAttribute("userId") String userId, String path) throws IOException {
        Result<JSONObject> res = new Result<>();
        String userPath = getUserPath(userId, path);
        File file = new File(userPath);
        String fileName = file.getName();
        JSONObject outPutObj = new JSONObject();

        if (fileName.lastIndexOf(".") != -1) {
            String extention = fileName.substring(fileName.lastIndexOf(".") + 1);
            switch (extention) {
                case "csv":
                    outPutObj.put("data", LocalFileIOUtil.csvPreview(userPath, true, PREVIEW_SIZE));
                    outPutObj.put("type", "Table");
                    break;
                case "txt":
                    outPutObj.put("data", LocalFileIOUtil.txtPreview(userPath));
                    outPutObj.put("type", "Table");
                    break;
                case "shp":
                    outPutObj.put("data", ReadShpFileBySize(userPath, PREVIEW_SIZE));
                    outPutObj.put("type", "Table");
                    break;
                case "json":
                    outPutObj.put("type", "Table");
                    break;
                case "png":
                    outPutObj.put("type", "pic");
                    break;
                default:
                    outPutObj.put("type", "txt");
                    break;
            }
        } else {
            outPutObj.put("type", "unknow");
        }
        return res.setBody(outPutObj).setCode(CodeConstants.SUCCESS);
    }

    private List<Map<String, String>> ReadShpFileBySize(String path, int size) {
        List<Map<String, String>> result = new ArrayList<>();
        ShpFileReader reader = new ShpFileReader();
        reader.filename(path);
        reader.init();
        String[] headers = reader.getHeaders();
        while (size > result.size()) {
            String[] oneLine = reader.next().split(TAB.getValue());
            Map<String, String> item = new HashMap<>();
            for (int i = 0; i < headers.length; i++) {
                item.put(headers[i], oneLine[i]);
            }
            result.add(item);
        }
        reader.close();
        return result;
    }

    private static String getPrintSize(long size) {
        if (size < 1024) {
            return size + "B";
        } else {
            size = size / 1024;
        }
        if (size < 1024) {
            return size + "KB";
        } else {
            size = size / 1024;
        }
        if (size < 1024) {
            size = size * 100;
            return (size / 100) + "." + (size % 100) + "MB";
        } else {
            size = size * 100 / 1024;
            return (size / 100) + "." + (size % 100) + "GB";
        }
    }

    private String getUserPath(String id, String path) {
        return fileSetting.getSelfDataNameSpace() + id + path;
    }
}
